<?php
// +----------------------------------------------------------------------
// | Bwsaas
// +----------------------------------------------------------------------
// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Gitee ( https://gitee.com/buwangyun/bwsaas )
// +----------------------------------------------------------------------
// | Author: buwangyun <hnlg666@163.com>
// +----------------------------------------------------------------------
// | Date: 2020-9-28 10:55:00
// +----------------------------------------------------------------------

namespace buwang\util;

use think\facade\Cache;
use buwang\traits\JwtTrait;
use app\manage\model\Member;
use app\common\model\MemberMiniapp;
use app\common\model\Miniapp;
use dh2y\qrcode\QRcode;
use upload\Uploadfile;
use think\file\UploadedFile;
use buwang\facade\WechatProgram;

//微信公众号
class Util
{
    use JwtTrait;

    /**
     * 字符串命名风格转换
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
     * @access public
     * @param string $name 字符串
     * @param integer $type 转换类型
     * @param bool $ucfirst 首字母是否大写（驼峰规则）
     * @return string
     */
    public static function parseName($name, $type = 0, $ucfirst = true)
    {
        if ($type) {
            $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
                return strtoupper($match[1]);
            }, $name);
            return $ucfirst ? ucfirst($name) : lcfirst($name);
        }

        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
    }

    /**
     * 清除模版缓存 不删除cache目录
     */
    public static function clear_sys_cache()
    {
        Cache::clear();
        return true;
    }

    public static function toreplace($str, $find)//$str是你需要操作的字符串,$find是你指定的字符串
    {
        if (strpos($str, $find) === false) return false;

        $a = explode($find, $str);
        return $a[0] . $find;
    }


    /**
     * 无限级归类
     *
     * @param array $list 归类的数组
     * @param string $id 父级ID
     * @param string $pid 父级PID
     * @param string $child key
     * @param string $root 顶级
     *
     * @return array
     */
    public static function tree(array $list, string $pk = 'id', string $pid = 'pid', string $child = 'child', int $root = 0): array
    {
        $tree = [];  //最终得到的树形数据

        if (is_array($list)) {
            $refer = [];

            //基于数组的指针(引用) 并 同步改变数组
            foreach ($list as $key => $val) {
                $list[$key][$child] = [];
                $refer[$val[$pk]] = &$list[$key];  //以主键为下标，值为列表数据的引用
            }


            foreach ($list as $key => $val) {
                //是否存在parent
                $parentId = isset($val[$pid]) ? $val[$pid] : $root;  //取出父级id

                //如果是根节点，直接放入根层级(实际放入的是一个组装好的树分支)
                if ($root == $parentId) {
                    $tree[$val[$pk]] = &$list[$key];
                } else {  //如果是其他节点，通过引用传入树分支


                    if (isset($refer[$parentId])) {

                        $refer[$parentId][$child][] = &$list[$key];  //1  3  4

                    }
                }

            }
            // die;
        }
        //var_dump(array_values($tree));
        return array_values($tree);
    }


    /**
     * 排列组合
     *
     * @param array $input 排列的数组
     *
     * @return array
     */
    static public function arrayArrange(array $input): array
    {
        $temp = [];
        $result = array_shift($input);  //挤出数组第一个元素
        $i = 0;
        while ($item = array_shift($input))  //循环每次挤出数组的一个元素，直到数组元素全部挤出
        {
            $temp = $result;
            $result = [];
            //var_dump('temp',$temp);
            foreach ($temp as $v) {
                foreach ($item as $val) {
                    //var_dump('排列组合',array_merge_recursive($v, $val));
                    $result[] = array_merge_recursive($v, $val);

                }
            }
            //var_dump('第'.++$i.'页',$result);
        }
        //die;
        return $result;
    }

    /**
     * 富文本base64解码
     */
    public static function r_text_decode($text)
    {
        $text = base64_decode($text);
        //var_dump($r_textarea);die;
        return htmlspecialchars_decode(urldecode($text));
    }


    /**取$member_id 不传如果是租户或者用户则自动查询$member_id
     * @return array|mixed
     */
    public static function getLoginMemberId($member_id = null, $dir = null)
    {
        $jwtinfo = null;
        $scopes = '';
        $service_id = null;
        $member_miniapp = null;
        $request = app("app\Request");//得到注入的request单例
        $token = get_token($request);//得到token
        try {
            if ($token) $jwtinfo = self::decodeToken($token);//解析token,获取用户信息
        } catch (\Throwable $e) {
            $jwtinfo = null;
        }
        //根据登录情况判断取配置值的权限
        $memberId = $member_id;
        $Dir = $dir;
        $header = $request->header();
        if (isset($header['request-app'])) $service_id = $header['request-app'];
        if ($jwtinfo) {
            $scopes = $jwtinfo->scopes;
            //租户登录 取顶级租户配置
            if ($jwtinfo->scopes == 'member' && $member_id === null) {
                $topuser = Member::getTop($jwtinfo->data->id);
                if ($topuser && isset($topuser['id'])) $memberId = $topuser['id'];
            }

//            //用户登录 根据服务id取顶级租户配置
//            if (!in_array($jwtinfo->scopes, ['member', 'admin']) && $member_id === null) {
//                if ($service_id) {
//                    //获取服务实例
//                    $MemberMiniapp = MemberMiniapp::where('service_id', $service_id)->find();
//                    if ($MemberMiniapp && isset($MemberMiniapp['member_id'])) {
//                        //查询顶级租户
//                        $topuser = Member::getTop($MemberMiniapp['member_id']);
//                        if ($topuser && isset($topuser['id'])) $memberId = $topuser['id'];
//                    }
//                }
//            }
            //admin登录但传了$member_id，则也查租户配置
            if ($jwtinfo->scopes == 'admin' && $member_id) {
                $topuser = Member::getTop($member_id);
                if ($topuser && isset($topuser['id'])) $memberId = $topuser['id'];
            }
        } elseif ($member_id) {
            //如果没登录但是传了$member_id，则也可查租户配置
            $topuser = Member::getTop($member_id);
            if ($topuser && isset($topuser['id'])) $memberId = $topuser['id'];
        }

        if ($service_id) {
            //获取服务实例
            $MemberMiniapp = MemberMiniapp::where('service_id', $service_id)->find();
            if ($MemberMiniapp && isset($MemberMiniapp['member_id'])) {
                $member_miniapp = $MemberMiniapp;
                if (!$member_id) {
                    //查询顶级租户
                    $topuser = Member::getTop($MemberMiniapp['member_id']);
                    if ($topuser && isset($topuser['id'])) $memberId = $topuser['id'];
                }
                //加入应用配置赛选
                if (!$Dir) {
                    //得到应用的dirId
                    $miniapp = Miniapp::find($MemberMiniapp['miniapp_id']);
                    if ($miniapp && isset($miniapp['dir'])) $Dir = $miniapp['dir'];
                }
            }
        }
        if (!$Dir) {
            $Dir = app('http')->getName();
        }

        //不是租户登录也没传租户id则返回默认值
        // if(!$memberId)return $default;

        return ['memberId' => $memberId, 'scopes' => $scopes, 'dir' => $Dir, 'jwtinfo' => $jwtinfo,'member_miniapp'=>$member_miniapp];
    }


    /**
     * 获取二维码
     * @param $url
     * @param $name
     * @return array|bool|string
     */
    public static function getQRCodePath($url, $name)
    {
//        var_dump(111);die;
        if (!strlen(trim($url)) || !strlen(trim($name))) return false;
        try {
            $upload = [];
            $outfile = config('qrcode.cache_dir');  //本地缓存地址
            $code = new QRcode();
            $wapCodePath = $code->png($url, $outfile . '/' . $name)->getPath(); //获取二维码生成的地址
            //得到二维码的文件流
            $content = file_get_contents('.' . $wapCodePath);
            $files = new UploadedFile('.' . $wapCodePath, $name, 'image/jpeg');

            $uploadConfig = bw_config('base');//得到所有基础配置
            $uploadConfig['upload_allow_type'] = "local,alioss,qnoss,txcos";
            //得到第三方服务器上传相关配置
            if ($uploadConfig['upload_type'] !== 'local') {
                $uploadConfig = array_merge($uploadConfig, bw_config($uploadConfig['upload_type']));
            }
            $upload = Uploadfile::instance()
                ->setUploadType($uploadConfig['upload_type'])
                ->setUploadConfig($uploadConfig)
                ->setFile($files)
                ->save();
            if ($upload['save'] == true) {
                return $upload['file_info'];
            } else {
                return $upload['msg'];
            }
        } catch (\Exception $e) {

            return $e->getMessage();
        }
    }


    /**
     * TODO 砍价 拼团 分享海报生成
     * @param array $data
     * @param $path
     * @return array|bool|string
     * @throws \Exception
     */
    public static function setShareMarketingPoster($data = array(), $path, $fileName)
    {
        if (!@fopen($data['image'], 'r')) throw new \Exception('缺少商品图片');
        if (!@fopen($data['url'], 'r')) throw new \Exception('缺少二维码图片');
        $config = array(
            'text' => array(
                array(
                    'text' => $data['price'],//TODO 价格
                    'left' => 116,
                    'top' => 200,
                    'fontPath' => app()->getRootPath() . 'public/static/font/Alibaba-PuHuiTi-Regular.otf',     //字体文件
                    'fontSize' => 50,             //字号
                    'fontColor' => '255,0,0',       //字体颜色
                    'angle' => 0,
                ),
                array(
                    'text' => $data['label'],//TODO 标签
                    'left' => 450,
                    'top' => 188,
                    'fontPath' => app()->getRootPath() . 'public/static/font/Alibaba-PuHuiTi-Regular.otf',     //字体文件
                    'fontSize' => 24,             //字号
                    'fontColor' => '255,255,255',       //字体颜色
                    'angle' => 0,
                ),
                array(
                    'text' => $data['msg'],//TODO 简述
                    'left' => 80,
                    'top' => 270,
                    'fontPath' => app()->getRootPath() . 'public/static/font/Alibaba-PuHuiTi-Regular.otf',     //字体文件
                    'fontSize' => 22,             //字号
                    'fontColor' => '40,40,40',       //字体颜色
                    'angle' => 0,
                )
            ),
            'image' => array(
                array(
                    'url' => $data['image'],     //图片
                    'stream' => 0,
                    'left' => 120,
                    'top' => 340,
                    'right' => 0,
                    'bottom' => 0,
                    'width' => 450,
                    'height' => 450,
                    'opacity' => 100
                ),
                array(
                    'url' => $data['url'],     //二维码资源
                    'stream' => 0,
                    'left' => 260,
                    'top' => 890,
                    'right' => 0,
                    'bottom' => 0,
                    'width' => 160,
                    'height' => 160,
                    'opacity' => 100
                )
            ),
            'background' => 'static/bwmall/poster/poster.jpg'
        );
        if (!file_exists($config['background'])) throw new \Exception('缺少系统预设背景图片');
        if (strlen($data['title']) < 36) {
            $text = array(
                'text' => $data['title'],//TODO 标题
                'left' => 76,
                'top' => 100,
                'fontPath' => app()->getRootPath() . 'public/static/font/Alibaba-PuHuiTi-Regular.otf',     //字体文件
                'fontSize' => 32,         //字号
                'fontColor' => '0,0,0',       //字体颜色
                'angle' => 0,
            );
            array_push($config['text'], $text);
        } else {
            $titleOne = array(
                'text' => mb_strimwidth($data['title'], 0, 24),//TODO 标题
                'left' => 76,
                'top' => 70,
                'fontPath' => app()->getRootPath() . 'public/static/font/Alibaba-PuHuiTi-Regular.otf',     //字体文件
                'fontSize' => 32,         //字号
                'fontColor' => '0,0,0',       //字体颜色
                'angle' => 0,
            );
            $titleTwo = array(
                'text' => mb_strimwidth($data['title'], mb_strlen(mb_strimwidth($data['title'], 0, 24)), 24),//TODO 标题
                'left' => 76,
                'top' => 120,
                'fontPath' => app()->getRootPath() . 'public/static/font/Alibaba-PuHuiTi-Regular.otf',     //字体文件
                'fontSize' => 32,         //字号
                'fontColor' => '0,0,0',       //字体颜色
                'angle' => 0,
            );
            array_push($config['text'], $titleOne);
            array_push($config['text'], $titleTwo);
        }
        return self::setSharePoster($config, $path, $fileName);
    }

    /**
     * TODO 生成分享二维码图片
     * @param array $config
     * @param $path
     * @return array|bool|string
     * @throws \Exception
     */
    public static function setSharePoster($config = array(), $path, $fileName)
    {
        //默认嵌入的图片配置
        $imageDefault = array(
            'left' => 0,
            'top' => 0,
            'right' => 0,
            'bottom' => 0,
            'width' => 100,
            'height' => 100,
            'opacity' => 100
        );
        //默认嵌入的文字配置
        $textDefault = array(
            'text' => '',
            'left' => 0,
            'top' => 0,
            'fontSize' => 32,       //字号
            'fontColor' => '255,255,255', //字体颜色
            'angle' => 0,
        );
        $background = $config['background'];//海报最底层得背景
        if (substr($background, 0, 1) === '/') {
            $background = substr($background, 1);
        }
        $backgroundInfo = getimagesize($background);
        $background = imagecreatefromstring(file_get_contents($background));
        $backgroundWidth = $backgroundInfo[0];  //背景宽度
        $backgroundHeight = $backgroundInfo[1];  //背景高度
        $imageRes = imageCreatetruecolor($backgroundWidth, $backgroundHeight);
        $color = imagecolorallocate($imageRes, 0, 0, 0);
        imagefill($imageRes, 0, 0, $color);
        imagecopyresampled($imageRes, $background, 0, 0, 0, 0, imagesx($background), imagesy($background), imagesx($background), imagesy($background));
        if (!empty($config['image'])) {
            foreach ($config['image'] as $key => $val) {
                $val = array_merge($imageDefault, $val);
                $info = getimagesize($val['url']);
                $function = 'imagecreatefrom' . image_type_to_extension($info[2], false);
                if ($val['stream']) {
                    $info = getimagesizefromstring($val['url']);
                    $function = 'imagecreatefromstring';
                }
                $res = $function($val['url']);
                $resWidth = $info[0];
                $resHeight = $info[1];
                $canvas = imagecreatetruecolor($val['width'], $val['height']);
                imagefill($canvas, 0, 0, $color);
                imagecopyresampled($canvas, $res, 0, 0, 0, 0, $val['width'], $val['height'], $resWidth, $resHeight);
                $val['left'] = $val['left'] < 0 ? $backgroundWidth - abs($val['left']) - $val['width'] : $val['left'];
                $val['top'] = $val['top'] < 0 ? $backgroundHeight - abs($val['top']) - $val['height'] : $val['top'];
                imagecopymerge($imageRes, $canvas, $val['left'], $val['top'], $val['right'], $val['bottom'], $val['width'], $val['height'], $val['opacity']);//左，上，右，下，宽度，高度，透明度
            }
        }
        if (isset($config['text']) && !empty($config['text'])) {
            foreach ($config['text'] as $key => $val) {
                $val = array_merge($textDefault, $val);
                list($R, $G, $B) = explode(',', $val['fontColor']);
                $fontColor = imagecolorallocate($imageRes, $R, $G, $B);
                $val['left'] = $val['left'] < 0 ? $backgroundWidth - abs($val['left']) : $val['left'];
                $val['top'] = $val['top'] < 0 ? $backgroundHeight - abs($val['top']) : $val['top'];
                imagettftext($imageRes, $val['fontSize'], $val['angle'], $val['left'], $val['top'], $fontColor, $val['fontPath'], $val['text']);
            }
        }
        ob_start();
        imagejpeg($imageRes);
        imagedestroy($imageRes);
        $res = ob_get_contents();//文件二进制流
        ob_end_clean();
        try {
            $uploadConfig = bw_config('base');//得到所有基础配置
            $uploadConfig['upload_allow_type'] = "local,alioss,qnoss,txcos";
            //得到第三方服务器上传相关配置
            if ($uploadConfig['upload_type'] !== 'local') {
                $uploadConfig = array_merge($uploadConfig, bw_config($uploadConfig['upload_type']));
            }
            $outfile = config('qrcode.cache_dir');  //本地缓存地址
            if (!file_exists('./' . $outfile . $path)) mkdir('./' . $outfile . $path, 0777, true);
            $filepath = './' . $outfile . $path . '/' . $fileName;
            file_put_contents($filepath, $res);
            $files = new UploadedFile($filepath, $fileName, 'image/jpeg');
            $upload = Uploadfile::instance()
                ->setUploadType($uploadConfig['upload_type'])
                ->setUploadConfig($uploadConfig)
                ->setFile($files)
                ->save();
            if ($upload['save'] == true) {
                return $upload['file_info'];
            } else {
                return $upload['msg'];
            }

        } catch (\Exception $e) {
            return $e->getMessage();
        }
    }


    /**
     * 获取小程序二维码
     * @param $url
     * @param $name
     * @return array|bool|string
     */
    public static function getMiniQRCodePath($url, $param, $name, $app_id)
    {
        if (!strlen(trim($url)) || !strlen(trim($name))) return false;
        try {
            $upload = [];
            $outfile = config('qrcode.cache_dir') . '/';  //本地缓存地址
            //生成小程序二维码
            $app = WechatProgram::getWechatObj($app_id);
            if (!$app) return '微信认证失败,请确认应用已授权.';
            $response = $app->app_code->getUnlimit(http_build_query($param), [
                'page' => $url,
                'width' => 280,
            ]);
            //正确返回
            if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
                //保存临时地址
                $filename = $response->saveAs($outfile, 'appcode.png');

                $wapCodePath = '/' . str_replace('\\', '/', $outfile . $filename);
                //var_dump($wapCodePath);die;
            } else {
                //错误返回
                return '生成小程序码错误' . $response['errcode'] . '：' . $response['errmsg'];
            }
            //保存到第三方文件
            $files = new UploadedFile('.' . $wapCodePath, $name, 'image/jpeg');
            $uploadConfig = bw_config('base');//得到所有基础配置
            $uploadConfig['upload_allow_type'] = "local,alioss,qnoss,txcos";
            //得到第三方服务器上传相关配置
            if ($uploadConfig['upload_type'] !== 'local') {
                $uploadConfig = array_merge($uploadConfig, bw_config($uploadConfig['upload_type']));
            }
            $upload = Uploadfile::instance()
                ->setUploadType($uploadConfig['upload_type'])
                ->setUploadConfig($uploadConfig)
                ->setFile($files)
                ->save();
            if ($upload['save'] == true) {
                return $upload['file_info'];
            } else {
                return $upload['msg'];
            }
        } catch (\Exception $e) {

            return $e->getMessage();
        }
    }

    //解密小程序的加密信息
    public static function getMiniDataValue($app_id, $session, $iv, $encryptedData)
    {
        //生成小程序二维码
        $app = WechatProgram::getWechatObj($app_id);
        if (!$app) throw new Exception('微信认证失败,请确认应用已授权');
        return $app->encryptor->decryptData($session, $iv, $encryptedData);
    }



}